#pragma once
#include "server.hpp"
#include <fstream>
#include <filesystem>
#include <regex>

extern Log lg;
class Util
{
public:
    // 将字符串按指定分割成多个
    static size_t split(const std::string& str, std::vector<std::string>* strs, const std::string& sep)
    {
        size_t pos = 0, next = 0;
        while ((next = str.find(sep, pos)) != std::string::npos)
        {
            if (next - pos)
                strs->push_back(str.substr(pos, next - pos));
            pos = next + sep.size();
        }
        if (pos != str.size())
            strs->push_back(str.substr(pos));
        return strs->size();
    }
    // 将一个字符串的所有字母都转换成大写
    static void alphaToUp(std::string& str) {
        std::transform(str.begin(), str.end(), str.begin(), [](char c) { return toupper(c);});
    }

    // 读取文件内容到一个字符串中
    static bool readFile(const std::string& fileName, std::string* str)
    {
        std::ifstream fin(fileName, std::ios::binary);
        if (!fin.is_open())
        {
            lg(Warning, "open file %s error", fileName.c_str());
            return false;
        }
        // 由于读取的数据可能是二进制数据，所以需要用read的方式进行读取
        // 1. 获取文件长度
        fin.seekg(0, fin.end);
        size_t fsize = fin.tellg();
        fin.seekg(0, fin.beg);
        // 2. 将内容写入string中
        std::string ret;
        ret.resize(fsize);
        fin.read(&ret[0], fsize);
        // 判断当前操作是否出现错误
        if (!fin.good())
        {
            lg(Warning, "read file: %s operation is error", fileName.c_str());
            return false;
        }
        *str = std::move(ret);
        return true;
    }
    // 将字符串中的内容写入文件中
    static bool writeFile(const std::string& file, const std::string& str)
    {
        // 默认全都以覆盖的方式写入
        std::ofstream fout(file, std::ios::binary | std::ios::trunc);
        lg(Info, "file name: %s, size: %u", file.c_str(), file.size());
        if (!fout.is_open())
        {
            lg(Warning, "open file: %s error", file.c_str());
            return false;
        }
        fout.write(str.c_str(), str.size());
        if (!fout.good())
        {
            lg(Warning, "write message to file: %s error", file.c_str());
            return false;
        }
        return true;
    }

    // 对字符串进行编码的工具
    // 不编码的特殊字符： RFC3986文档规定 . - _ ~ 字母，数字属于绝对不编码字符
    // RFC3986文档规定，编码格式 %HH 
    // W3C标准中规定，查询字符串中的空格，需要编码为+， 解码则是+转空格
    static std::string encodeUrl(std::string url, bool needReverSpace = true)
    {
        std::string ret;
        for (auto ch : url)
        {
            // 判断是不是绝对不编码字符
            if (ch == '.' || ch == '-' || ch == '_' || ch == '~' || isalnum(ch))
                ret += ch;
            else if (ch == ' ')
            {
                if (needReverSpace) ret += '+';
                else ret += ' ';
            }
            else
            {
                // 利用snprintf将数字转换成十六进制字符串
                char tmp[5] = { 0 };
                snprintf(tmp, 5, "%%%02X", ch);
                ret += tmp;
            }
        }
        return ret;
    }
private:
    static char htod(const std::string& str, size_t x)
    {
        char ch = 0;
        for (int i = 0; i < 2; ++i)
        {
            int tmp = 0;
            if (str[x + i] >= 'A' && str[x + i] <= 'Z')
                tmp = str[x + i] - 'A' + 10;
            else if (str[x + i] >= 'a' && str[x + i] <= 'z')
                tmp = str[x + i] - 'a' + 10;
            else
                tmp = str[x + i] - '0';
            ch = (ch << 4) + tmp;
        }
        return ch;
    }
public:
    static std::string decodeUrl(const std::string& str, bool needReverSpace = true)
    {
        std::string ret;
        for (size_t i = 0; i < str.size(); ++i)
        {
            if (str[i] == '%')
            {
                ret += htod(str, i + 1);
                i += 2;
            }
            else if (str[i] == '+')
            {
                if (needReverSpace) ret += ' ';
                else ret += '+';
            }
            else
                ret += str[i];
        }
        return ret;
    }
    // 根据状态码获取对应的状态描述
    static std::string getStatStr(const int stat)
    {
        static std::unordered_map<int, std::string> statHash{
            {100,  "Continue"},
            {101,  "Switching Protocol"},
            {102,  "Processing"},
            {103,  "Early Hints"},
            {200,  "OK"},
            {201,  "Created"},
            {202,  "Accepted"},
            {203,  "Non-Authoritative Information"},
            {204,  "No Content"},
            {205,  "Reset Content"},
            {206,  "Partial Content"},
            {207,  "Multi-Status"},
            {208,  "Already Reported"},
            {226,  "IM Used"},
            {300,  "Multiple Choice"},
            {301,  "Moved Permanently"},
            {302,  "Found"},
            {303,  "See Other"},
            {304,  "Not Modified"},
            {305,  "Use Proxy"},
            {306,  "unused"},
            {307,  "Temporary Redirect"},
            {308,  "Permanent Redirect"},
            {400,  "Bad Request"},
            {401,  "Unauthorized"},
            {402,  "Payment Required"},
            {403,  "Forbidden"},
            {404,  "Not Found"},
            {405,  "Method Not Allowed"},
            {406,  "Not Acceptable"},
            {407,  "Proxy Authentication Required"},
            {408,  "Request Timeout"},
            {409,  "Conflict"},
            {410,  "Gone"},
            {411,  "Length Required"},
            {412,  "Precondition Failed"},
            {413,  "Payload Too Large"},
            {414,  "URI Too Long"},
            {415,  "Unsupported Media Type"},
            {416,  "Range Not Satisfiable"},
            {417,  "Expectation Failed"},
            {418,  "I'm a teapot"},
            {421,  "Misdirected Request"},
            {422,  "Unprocessable Entity"},
            {423,  "Locked"},
            {424,  "Failed Dependency"},
            {425,  "Too Early"},
            {426,  "Upgrade Required"},
            {428,  "Precondition Required"},
            {429,  "Too Many Requests"},
            {431,  "Request Header Fields Too Large"},
            {451,  "Unavailable For Legal Reasons"},
            {501,  "Not Implemented"},
            {502,  "Bad Gateway"},
            {503,  "Service Unavailable"},
            {504,  "Gateway Timeout"},
            {505,  "HTTP Version Not Supported"},
            {506,  "Variant Also Negotiates"},
            {507,  "Insufficient Storage"},
            {508,  "Loop Detected"},
            {510,  "Not Extended"},
            {511,  "Network Authentication Required"}
        };
        if (!statHash.count(stat))
            return "Unknow";
        else
            return statHash[stat];
    }
    // 根据文件后缀获得对应的http mime类型
    static std::string getMime(const std::string& fileName)
    {
        static std::unordered_map<std::string, std::string> mimeHash{
            {".aac",        "audio/aac"},
            {".abw",        "application/x-abiword"},
            {".arc",        "application/x-freearc"},
            {".avi",        "video/x-msvideo"},
            {".azw",        "application/vnd.amazon.ebook"},
            {".bin",        "application/octet-stream"},
            {".bmp",        "image/bmp"},
            {".bz",         "application/x-bzip"},
            {".bz2",        "application/x-bzip2"},
            {".csh",        "application/x-csh"},
            {".css",        "text/css"},
            {".csv",        "text/csv"},
            {".doc",        "application/msword"},
            {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
            {".eot",        "application/vnd.ms-fontobject"},
            {".epub",       "application/epub+zip"},
            {".gif",        "image/gif"},
            {".htm",        "text/html"},
            {".html",       "text/html"},
            {".ico",        "image/vnd.microsoft.icon"},
            {".ics",        "text/calendar"},
            {".jar",        "application/java-archive"},
            {".jpeg",       "image/jpeg"},
            {".jpg",        "image/jpeg"},
            {".js",         "text/javascript"},
            {".json",       "application/json"},
            {".jsonld",     "application/ld+json"},
            {".mid",        "audio/midi"},
            {".midi",       "audio/x-midi"},
            {".mjs",        "text/javascript"},
            {".mp3",        "audio/mpeg"},
            {".mpeg",       "video/mpeg"},
            {".mpkg",       "application/vnd.apple.installer+xml"},
            {".odp",        "application/vnd.oasis.opendocument.presentation"},
            {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
            {".odt",        "application/vnd.oasis.opendocument.text"},
            {".oga",        "audio/ogg"},
            {".ogv",        "video/ogg"},
            {".ogx",        "application/ogg"},
            {".otf",        "font/otf"},
            {".png",        "image/png"},
            {".pdf",        "application/pdf"},
            {".ppt",        "application/vnd.ms-powerpoint"},
            {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
            {".rar",        "application/x-rar-compressed"},
            {".rtf",        "application/rtf"},
            {".sh",         "application/x-sh"},
            {".svg",        "image/svg+xml"},
            {".swf",        "application/x-shockwave-flash"},
            {".tar",        "application/x-tar"},
            {".tif",        "image/tiff"},
            {".tiff",       "image/tiff"},
            {".ttf",        "font/ttf"},
            {".txt",        "text/plain"},
            {".vsd",        "application/vnd.visio"},
            {".wav",        "audio/wav"},
            {".weba",       "audio/webm"},
            {".webm",       "video/webm"},
            {".webp",       "image/webp"},
            {".woff",       "font/woff"},
            {".woff2",      "font/woff2"},
            {".xhtml",      "application/xhtml+xml"},
            {".xls",        "application/vnd.ms-excel"},
            {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
            {".xml",        "application/xml"},
            {".xul",        "application/vnd.mozilla.xul+xml"},
            {".zip",        "application/zip"},
            {".3gp",        "video/3gpp"},
            {".3g2",        "video/3gpp2"},
            {".7z",         "application/x-7z-compressed"}
        };
        size_t pos = fileName.rfind('.');
        if (pos == std::string::npos)
            return "text/html";
        std::string suffix = fileName.substr(pos);
        if (!mimeHash.count(suffix))
            return "text/html";
        else
            return mimeHash[suffix];
    }
    // 判断是不是一个普通文件
    static bool isDirectory(const std::string& path) { return std::filesystem::is_directory(path); }
    static bool isRegular(const std::string& path) { return std::filesystem::is_regular_file(path); }
    // 检查路径是否正确
    static bool validPath(const std::string& path)
    {
        int depth = 0;
        std::vector<std::string> paths;
        split(path, &paths, "/");
        for (const auto& str : paths)
        {
            if (str == "..")
            {
                --depth;
                if (depth < 0) return false;
            }
            ++depth;
        }
        return true;
    }
};

class httpInfo
{
public:
    std::unordered_map<std::string, std::string> _headers;
    std::string _content;
protected:
    bool findInHash(const std::string& key, const std::unordered_map<std::string, std::string>& hsh) const
    {
        if (hsh.count(key))
            return true;
        return false;
    }
    bool setInHash(bool cover, std::unordered_map<std::string, std::string>& hsh, const std::string& key, const std::string& value)
    {
        if (!cover && hsh.count(key))
            return false;
        hsh[key] = value;
        return true;
    }
    std::string getInHash(const std::string& key, std::unordered_map<std::string, std::string>& hsh)
    {
        if (findInHash(key, hsh))
            return hsh[key];
        else
            return "";
    }
public:  /*头部字段相关操作*/
    bool setHeader(const std::string& key, const std::string& value, bool cover = false) {
        return setInHash(cover, _headers, key, value);
    }
    bool hasHeader(const std::string& key) const {
        return findInHash(key, _headers);
    }
    std::string getHeader(const std::string& key) {
        return getInHash(key, _headers);
    }
public: /*判断是否是长连接*/
    bool isAliveLink()
    {
        static std::string connectType = "Connection";
        static std::string aliveType = "keep-alive";
        if (hasHeader(connectType) && _headers[connectType] == aliveType) return true;
        // 如果没有这个字段也是默认短链接
        return false;
    }
};

// 便于提取http请求的信息
class httpRequest : public httpInfo
{
public:
    std::unordered_map<std::string, std::string> _parms;
    std::string _method; // 查询方法
    std::string _path;   // 查询路径
    std::string _version;// 版本号
    std::smatch _matchs; // 正则表达式匹配的内容
    /*httpInfo内包含正文和header*/
public:
    httpRequest() = default;
    ~httpRequest() = default;
    void reset()
    {
        _headers.clear();
        _parms.clear();
        _method.clear();
        _path.clear();
        _content.clear();

        std::smatch tmp;
        _matchs.swap(tmp);
    }
public:  /*parm参数字段相关操作*/
    bool setParmStr(const std::string& key, const std::string& value, bool cover = false) {
        return setInHash(cover, _parms, key, value);
    }
    bool hasParmStr(const std::string& key) {
        return findInHash(key, _parms);
    }
    std::string getParmStr(const std::string& key) {
        return getInHash(key, _parms);
    }
public: /*其他接口*/
    size_t getContentLength()
    {
        static std::string contentL = "Content-Length";
        if (!hasHeader(contentL)) return 0;
        return std::stoi(_headers[contentL]);
    }

};

class httpResponse : public httpInfo
{
public:
    int _stat = 200;
    bool _isRedirect = false;
    std::string _redirectUrl;
    /*httpInfo里有通用的头部字段和正文字段*/
public:
    httpResponse() = default;
    httpResponse(const int stat) :_stat(stat) {}
    ~httpResponse() = default;
public:
    void SetContent(const std::string& body, const std::string& type = "text/html") {
        _content = body;
        static std::string contentType = "Content-Type";
        static std::string contentLen = "Content-Length";
        setHeader(contentType, type);
        setHeader(contentLen, std::to_string(body.size()));
    }
    void SetRedirect(const std::string& url, int statu = 302) {
        _stat = statu;
        _isRedirect = true;
        _redirectUrl = url;
    }
    std::string toStr(const std::string& version)
    {
        std::string tail = "\r\n";
        std::string ret;
        ret += version + ' ' + std::to_string(_stat) + ' ' + Util::getStatStr(_stat) + tail;
        for (const auto& [k, v] : _headers)
            ret += k + ": " + v + tail;
        ret += tail;
        if (_content.size())
            ret += _content;
        return ret;
    }
};


enum class httpRecvStat
{
    RecvErr,
    RecvLine,
    RecvHeader,
    RecvBody,
    RecvOver
};

class httpContext
{
    const size_t maxLineSize = 8192;
private:
    httpRequest _request;
    httpRecvStat _stat = httpRecvStat::RecvLine;
    int _statCode = 200;
public:
    httpContext() = default;
    ~httpContext() = default;
private:
    void longUriHandle()
    {
        _stat = httpRecvStat::RecvErr;
        _statCode = 414; // 此时的错误是uri的长度太长了
    }
    bool getProperLine(Buffer& buf, std::string* line)
    {
        // 1. 获取一行数据
        *line = buf.getline(false);
        // 如果没有一行
        if (line->empty())
        {
            // 如果缓冲区中的长度已经很长了，说明这个缓冲区是有问题的，直接返回false
            if (buf.getReadAbleSize() >= maxLineSize)
            {
                longUriHandle();
                return false;
            }
            // 如果数据不是很长，说明还有数据没有发送到位，直接退出
            return true;
        }
        // 如果成功读取到了一行数据，也要先判断长度会不会太长
        if (line->size() >= maxLineSize)
        {
            longUriHandle();
            return false;
        }
        return true;
    }
private:
    // 读取
    bool recvRequestLine(Buffer& buf)
    {
        if (_stat != httpRecvStat::RecvLine) return false;
        std::string line;
        // 如果缓冲区中的长度太长或者一行的长度太长，直接return false
        if (!getProperLine(buf, &line))
            return false;

        // 判断是不是请求行的格式
        bool ret = parseRequestLine(line);
        if (!ret)
            return false;

        // 如果处理成功，将缓冲区后移，并且将处理状态转换成下一个状态
        buf.readerIdxGo(line.size());
        _stat = httpRecvStat::RecvHeader;
        return true;
    }
    bool parseRequestParms(const std::string& parm)
    {
        std::vector<std::string> parms;
        Util::split(parm, &parms, "&");
        for (auto& str : parms)
        {
            // 如果查询字符串中没有等号，说明查询字符串是错误的
            size_t pos;
            if ((pos = str.find('=')) == std::string::npos)
                return false;
            // 由于传输中的查询字符串是没有转换的，所以在写入request的时候需要先解码
            std::string key = Util::decodeUrl(str.substr(0, pos));
            std::string value = Util::decodeUrl(str.substr(pos + 1));
            _request.setParmStr(key, value);
        }
        return true;
    }
    bool parseRequestLine(const std::string& line)
    {
        // 对请求行进行解析
        std::smatch matchs;
        // 忽略大小写匹配，避免不规范的请求
        static std::regex modle(R"((GET|HEAD|PUT|POST|DELETE|OPTIONS) ([^?]*)(?:\?(.*))? (HTTP/1\.[01])(?:\n|\r\n)?)", std::regex::icase);
        if (std::regex_match(line, matchs, modle) == false)
        {
            _stat = httpRecvStat::RecvErr;
            _statCode = 400; // bad request
            return false;
        }
        // 防止不规范的http请求
        _request._method = matchs[1];
        Util::alphaToUp(_request._method);

        // 路径也是需要解码的，不过不用转换空格
        _request._path = Util::decodeUrl(matchs[2], false);

        // 处理查询字符串
        if (!parseRequestParms(matchs[3]))
        {
            _stat = httpRecvStat::RecvErr;
            _statCode = 400; // bad request
            return false;
        }

        _request._version = matchs[4];
        return true;
    }

    bool parseHeader(std::string& line)
    {
        // 1. 首先将末尾的换行符和回车符删除
        if (line.back() == '\n') line.pop_back();
        if (line.back() == '\r') line.pop_back();

        // 2. 找到": " 的分割符，左边是key, 右边是value
        size_t pos = line.find(": ");
        if (pos == std::string::npos)
        {
            _stat = httpRecvStat::RecvErr;
            _statCode = 400;  // bad request
            return false;
        }

        // 3. 设置到request的头部字段内
        _request.setHeader(line.substr(0, pos), line.substr(pos + 2));
        return true;
    }

    // 读取头部数据
    bool recvHeader(Buffer& buf)
    {
        if (_stat != httpRecvStat::RecvHeader) return false;
        while (true)
        {
            // 1. 读取一行数据
            std::string line;
            if (!getProperLine(buf, &line))
                return false;
            buf.readerIdxGo(line.size());
            // 如果是空行，说明头部结束
            if (line == "\r\n" || line == "\n")
                break;

            // 分析字符串
            bool ret = parseHeader(line);
            if (!ret)
                return false;
        }
        _stat = httpRecvStat::RecvBody;
        return true;
    }

    bool recvBody(Buffer& buf)
    {
        if (_stat != httpRecvStat::RecvBody) return false;
        // 1. 获取字符长度
        size_t len = _request.getContentLength();
        if (!len)
        {
            _stat = httpRecvStat::RecvOver;
            return true;
        }
        // 如果缓冲区中数据不足，直接退出，等待数据足够
        if (buf.getReadAbleSize() < len) return true;

        // 读取缓冲区中的数据，并且将状态改为读取结束
        _request._content = buf.read(len);
        _stat = httpRecvStat::RecvOver;
        return true;
    }

public:
    int getStatCode() { return _statCode; }
    void reset()
    {
        _statCode = 200;
        _stat = httpRecvStat::RecvLine;
        _request.reset();
    }
    httpRequest& getRequest() { return _request; }
    httpRecvStat getParseStat() { return _stat; }
    void parseRequest(Buffer& buf)
    {
        switch (_stat)
        {
        case httpRecvStat::RecvLine:   recvRequestLine(buf);
        case httpRecvStat::RecvHeader: recvHeader(buf);
        case httpRecvStat::RecvBody:
            recvBody(buf);
            if (_stat != httpRecvStat::RecvErr) break;
        case httpRecvStat::RecvErr:
            lg(Warning, "parse request error");
        }
    }
};

class httpServer
{
    using handler = std::function<void(const httpRequest&, httpResponse*)>;
    using hanlderMap = std::vector<std::pair<std::regex, handler>>;
private:
    // 请求方式路由表
    tcpServer _server;
    hanlderMap _getHandlers;
    hanlderMap _postHandlers;
    hanlderMap _putHandlers;
    hanlderMap _deleteHandlers;
    // 静态妓院根目录
    std::string _baseDir;

public:
    httpServer(const uint16_t port, const size_t threadNum, const size_t maxOutTime = defaultMaxTimeOut, const size_t conOutTime = 10)
        :_server(port, threadNum, maxOutTime) {
        _server.setInactiveFree(conOutTime);
    }
    ~httpServer() = default;

private:
    // 当新连接创建时，为新连接创建一个上下文
    void onConnected(const ptrConnection& pcon)
    {
        pcon->setContext(httpContext());
        lg(Info, "connection, fd: %d make a new request", pcon->fd());
    }

private:
    // 请求错误返回的响应
    void handlerErr(httpResponse* prsp)
    {
        //1. 组织一个错误展示页面
        std::string body;
        body += "<html>";
        body += "<head>";
        body += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'>";
        body += "</head>";
        body += "<body>";
        body += "<h1>";
        body += std::to_string(prsp->_stat) + ' ' + Util::getStatStr(prsp->_stat);
        body += "</h1>";
        body += "</body>";
        body += "</html>";
        // 2. 将内容设置到响应中去
        prsp->SetContent(body);
    }
    // 将响应发送到对端
    void writeResponse(const ptrConnection& pcon, httpRequest& req, httpResponse& rsp)
    {
        // 完善头部字段
        // 确认是否是长连接
        if (req.isAliveLink() == true)
            rsp.setHeader("Connection", "keep-alive");
        // 确认字段是否都设置了，提高健壮性
        if (rsp._content.size() && !rsp.hasHeader("Content-Type"))
            rsp.setHeader("Content-Type", "text/html");
        if (rsp._content.size() && !rsp.hasHeader("Content-Type"))
            rsp.setHeader("Content-Length", std::to_string(rsp._content.size()));
        // 确认是否需要重定向
        if (rsp._isRedirect)
            rsp.setHeader("Location", rsp._redirectUrl);
        std::string rspon = rsp.toStr(req._version);
        pcon->send(rspon.c_str(), rspon.size());
    }

private: /*http请求业务处理模块*/
    // 检查是否是静态资源请求
    bool isfileHandler(const httpRequest& req)
    {
        // 1. 如果没有设置静态资源根目录，直接返回
        if (_baseDir.empty())
            return false;
        // 2. 如果不是GET或者HEAD方法，直接返回
        if (req._method != "GET" && req._method != "HEAD")
            return false;

        // 3. 判断用户请求的资源是否合法
        if (!Util::validPath(req._path))
            return false;

        // 4. 查看查询的资源是否存在
        std::string path = _baseDir + req._path;

        // 这里要注意如果是以/结尾，默认加上index.html
        std::string index = "index.html";
        if (path.back() == '/')
            path += std::move(index);
        if (!Util::isRegular(path))
            return false;
        return true;
    }
    // 进行静态资源请求
    void fileHandler(const httpRequest& req, httpResponse* prsp)
    {
        std::string path = _baseDir + req._path;
        std::string index = "index.html";
        if (path.back() == '/')
            path += std::move(index);
        std::string file;
        bool ret = Util::readFile(path, &file);
        if (!ret)
        {
            // 文件读取出错，说明服务器出现问题
            lg(Warning, "read file error, file:%s", path.c_str());
            prsp->_stat = 500;
            handlerErr(prsp);
            return;
        }
        prsp->SetContent(file, Util::getMime(path));
    }
    // 进行功能性请求
    void dispatcher(httpRequest& req, const hanlderMap& map, httpResponse* prsp)
    {
        for (const auto& [reg, func] : map)
            if (std::regex_match(req._path, req._matchs, reg))
                return func(req, prsp);
        // 如果没有一个匹配成功，直接返回404
        prsp->_stat = 404;
        handlerErr(prsp);
    }

    // 根据完整请求进行选择对应操作
    void route(httpRequest& req, httpResponse* prsp)
    {
        // 1. 先判断是不是静态资源请求，如果是直接处理，不是进入功能性请求中
        if (isfileHandler(req))
            return fileHandler(req, prsp);
        // 2. 根据各种不同的请求去不同路由表中分配任务
        if (req._method == "GET" || req._method == "HEAD")
            return dispatcher(req, _getHandlers, prsp);
        if (req._method == "DELETE")
            return dispatcher(req, _deleteHandlers, prsp);
        if (req._method == "PUT")
            return dispatcher(req, _putHandlers, prsp);
        if (req._method == "POST")
            return dispatcher(req, _postHandlers, prsp);
        // 如果请求方式全部匹配失败，返回405
        prsp->_stat = 405;
        handlerErr(prsp);
    }

private:

    // 当对端消息到来时，为该消息进行数据处理
    void httpProtocol(const ptrConnection& pcon, Buffer& buf)
    {
        while (!buf.empty())
        {
            // 如果此时缓冲区已经没有数据了，那就直接退出数据处理
            if (buf.empty()) return;
            // 1. 获取http上下文数据
            httpContext* context = std::any_cast<httpContext>(&pcon->getContext());
            // 2. 对request中的数据进行解析
            context->parseRequest(buf);
            auto stat = context->getParseStat();
            auto& req = context->getRequest();
            httpResponse rsp(context->getStatCode());
            // 3. 处理后有三种情况
            // 如果在获取请求过程中出错，直接进行错误响应
            if (stat == httpRecvStat::RecvErr)
            {
                lg(Info, "parse request error, send error page to client, connection fd: %d", pcon->fd());
                handlerErr(&rsp);
                writeResponse(pcon, req, rsp);
                // 请求出错，清空缓冲区，关闭连接
                buf.clear();
                pcon->close();
                return;
            }
            // 如果请求还未接收完全，直接返回，等待下次处理
            else if (stat != httpRecvStat::RecvOver)
                return;
            // 说明已经获得了完整的请求，可以进行下一步的处理
            // 根据请求进行路由寻找操作
            route(req, &rsp);
            writeResponse(pcon, req, rsp);
            // 如果不是长连接，处理完一次之后，直接关闭连接
            if (!req.isAliveLink())
            {
                buf.clear();
                pcon->close();
                return;
            }
            context->reset();
        }
    }
private:
public:
    void setBaseDir(const std::string& path) { _baseDir = path; }
    void Get(const std::string& pattern, const handler& hand) {
        _getHandlers.push_back({ std::regex(pattern), hand });
    }
    void Post(const std::string& pattern, const handler& hand) {
        _postHandlers.push_back({ std::regex(pattern), hand });
    }
    void Delete(const std::string& pattern, const handler& hand) {
        _deleteHandlers.push_back({ std::regex(pattern), hand });
    }
    void Put(const std::string& pattern, const handler& hand) {
        _putHandlers.push_back({ std::regex(pattern), hand });
    }

    // 初始化服务器
    void init() {
        _server.setConnectedCb([this](const ptrConnection& pcon) { this->onConnected(pcon); });
        _server.setProtocolCb([this](const ptrConnection& pcon, Buffer& buf) { this->httpProtocol(pcon, buf); });
        _server.init();
    }
    // 启动服务器
    void start() { _server.start(); }
};